﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms.DataVisualization.Charting;
using PGMHelper;

namespace HystereticBasic
{
    /// <summary>
    /// 多圈滞回环对象
    /// </summary>
    public class CycleSet
    {
        /// <summary>
        /// 滞回环列表
        /// </summary>
        private List<Cycle> CycleList { set; get; }

        /// <summary>
        /// 加载卸载路径
        /// </summary>
        private LoadingPathSet loadingPathes { set; get; }

        /// <summary>
        /// 滞回环的数目
        /// </summary>
        public int Count
        {
            get
            {
                return this.CycleList.Count;
            }
        }

        /// <summary>
        /// 获得滞回环
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Cycle this[int index]
        {
            get
            {
                if (index >= this.Count) return new Cycle(index);
                return this.CycleList[index];
            }
        }

        /// <summary>
        /// 是否滞回环数据
        /// </summary>
        public bool isCyclic
        {
            get
            {
                return this.GetFilterCircleList(false, true).Count >= 2;
            }
        }

        /// <summary>
        /// 是否双向往复数据
        /// </summary>
        public bool isReverseCyclic
        {
            get
            {
                return this.GetFilterDirectionCircleList(true, false, true).Count >= 2 &&
                   this.GetFilterDirectionCircleList(false, false, true).Count >= 2;
            }
        }

        #region 获得滞回环

        /// <summary>
        /// 获得相近位移过滤后的滞回环
        /// </summary>
        /// <returns></returns>
        private List<Cycle> GetFilterCircleList(bool isFilter, bool exclude24Obj)
        {
            //满足要求的滞回环
            var posCycles = this.GetFilterDirectionCircleList(true, isFilter, exclude24Obj);
            var negCycles = this.GetFilterDirectionCircleList(false, isFilter, exclude24Obj);
            //获得序号
            var indexList = posCycles.GetPropertyList("Index").ConvertAll(i => (int)i);
            //添加其他序号
            indexList.AddRange((from cycle in negCycles
                                where !indexList.Contains(cycle.Index)
                                select cycle.Index).ToList());
            //排序
            indexList.Sort();
            //返回对象
            return (from index in indexList select this[index - 1]).ToList();
        }

        /// <summary>
        /// 获得相近位移过滤后的滞回环
        /// </summary>
        /// <returns></returns>
        private List<Cycle> GetFilterDirectionCircleList(bool isPos, bool isFilter, bool exclude24Obj)
        {
            //初始化
            var cycleList = new List<Cycle>();
            //最大变形
            float maxDisp = 0;
            //添加对象
            Action<Cycle> addCycle = (cycle) =>
            {
                cycleList.Add(cycle);
                maxDisp = cycle.GetMaxDisp(isPos);
            };
            //遍历所有环
            foreach (var cycle in this.CycleList)
            {
                //存在数据 判断容差
                var curMaxDisp = cycle.GetMaxDisp(isPos);
                //当前变形为零
                if (Math.Abs(curMaxDisp) < GlobalParam.DispTol) continue;
                //指向点落入2 4象限
                if(exclude24Obj && cycle.isPeakOreintedInRegion24(isPos)) continue; 
                //计算粘滞阻尼系数
                var dampRatio = cycle.GetViscousDampingRatio(isPos);
                //粘滞阻尼系数越界
                if (dampRatio > GlobalParam.ValidViscousDampingRatio) continue;
                //没有数据
                if (cycleList.Count == 0) addCycle(cycle);
                //存在数据，需要过滤滞回环
                else if(isFilter)
                {
                    //误差较小
                    if (Math.Abs(curMaxDisp - maxDisp) < GlobalParam.DispTol) continue;
                    //控制相对误差
                    if (Math.Abs((curMaxDisp - maxDisp) / curMaxDisp) < GlobalParam.FilterCyclicFactor)
                        continue;
                    //添加环
                    addCycle(cycle);
                }
                else addCycle(cycle);
            }
            //返回滞回环
            return cycleList;
        }

        /// <summary>
        /// 获得滞回环数据
        /// </summary>
        /// <param name="isFilter"> 是否过滤等位移滞回环（仅保留第一滞回环） </param>
        /// <returns> 滞回环对象列表 </returns>
        public List<Cycle> GetCircleList(bool isFilter, bool excludeLastCycle, bool exclude24Obj = true)
        {
            //获得所有对象
            var cycleList = this.GetFilterCircleList(isFilter, exclude24Obj);
            //忽略无下降段的对象
            if (!excludeLastCycle || !this.isCyclic) return cycleList;
            //判断最后一个滞回环的粘滞系数是否满足要求（防止割线刚度计算有误）
            if (cycleList.Last().GetViscousDampingRatio(true) > GlobalParam.ValidViscousDampingRatio ||
                cycleList.Last().GetViscousDampingRatio(false) > GlobalParam.ValidViscousDampingRatio)
                cycleList.RemoveAt(cycleList.Count - 1);
            //返回滞回环数据
            return cycleList;
        }

        /// <summary>
        /// 获得滞回环数据
        /// </summary>
        /// <param name="isFilter"> 是否过滤等位移滞回环（仅保留第一滞回环） </param>
        /// <returns> 滞回环对象列表 </returns>
        public List<Cycle> GetDirectionCircleList(bool isFilter, bool isPos, bool exclude24Obj = true)
        {
            //获得所有对象
            return (from cyclic in this.GetFilterDirectionCircleList(isPos, isFilter, exclude24Obj) 
                             select cyclic).ToList();
        }

        #endregion

        #region Chart Data

        /// <summary>
        /// 绘制分解的滞回环
        /// </summary>
        /// <param name="chart"></param>
        public void CircleToChart(Chart chart, bool isFilter)
        {
            chart.Series.Clear();
            //遍历滞回环
            this.GetCircleList(isFilter, false).ForEach(circle => circle.ToChart(chart));
        }

        /// <summary>
        /// 绘制分解的滞回环
        /// </summary>
        /// <param name="chart"></param>
        public void CycleSetToChart(Chart chart, Color color, int borderWith, bool isSolid)
        {
            //遍历滞回环
            this.GetCircleList(false, false).ForEach(circle => 
            circle.ToChart(chart, color, borderWith, isSolid));
        }

        /// <summary>
        /// 获得数据
        /// </summary>
        /// <returns></returns>
        public GridViewDatas GetData(string title, bool isNorminal)
        {
            var data = new GridViewDatas();
            this.GetCircleList(false, false).ForEach(circle => data.AddRange(circle.GetData(title, isNorminal)));
            return data;
        }

        #endregion

        /// <summary>
        /// 获得耗能
        /// </summary>
        /// <returns></returns>
        public double GetEenergy()
        {
            return this.GetCircleList(false, false).Last().GetA();
        }

        /// <summary>
        /// 获得完整滞回曲线
        /// </summary>
        /// <param name="removePtNotOnCuver"></param>
        /// <returns></returns>
        private ForceDispObj GetWholeLoadPath(bool removePtNotOnCuver)
        {
            //初始化
            var obj = new ForceDispObj();
            var orderList = new List<int>();
            //遍历环
            this.GetCircleList(false, false).ForEach(cycle =>
            {
                //遍历加载路径
                foreach (var pair in cycle.WholeLoadPath.ToList())
                {
                    //不在曲线上的点
                    if(pair.Order == -1)
                    {
                        if (!removePtNotOnCuver) obj.Add(pair); 
                        continue;
                    }
                    //不重复添加数据点
                    if (orderList.Contains(pair.Order)) continue;
                    //添加对象
                    obj.Add(pair);
                    orderList.Add(pair.Order);
                }
            });
            //返回对象
            return obj;
        }

        /// <summary>
        /// 获得所有单调加载曲线
        /// </summary>
        /// <returns></returns>
        public List<MontForceDispObj> GetMonotonousList(bool isFilter, bool exclude24Obj)
        {
            //初始化
            var objList = new List<MontForceDispObj>();
            //添加对象
            Action<MontForceDispObj> addObj = (obj) =>
          {
              if (obj.Count != 0) objList.Add(obj);
          };
            //获得所有环
            foreach(var cycle in this.GetCircleList(isFilter, false, exclude24Obj))
            {
                //获得对象
                var forceObjList = cycle.GetMonotonousList(exclude24Obj);
                //是否存在现有对象
                if (objList.Count != 0)
                {
                    //获得最后对象
                    var lastObj = objList.Last();
                    //获得加载段
                    if (forceObjList[0].Count != 0)
                    {
                        for(int i = 1; i < forceObjList[0].Count; i++)
                        {
                            lastObj.Add(forceObjList[0][i]);
                        }
                    }
                    //二次加载段
                    addObj(forceObjList[1]);
                    addObj(forceObjList[2]);
                }
                else forceObjList.ForEach(obj => addObj(obj));
            }
            return objList;
        }

        /// <summary>
        /// 获得力时程曲线
        /// </summary>
        public List<float> Forces(bool removePtNotOnCuver)
        {
            return this.GetWholeLoadPath(removePtNotOnCuver).Forces;
        }

        /// <summary>
        /// 获得位移时程曲线
        /// </summary>
        public List<float> Disps(bool removePtNotOnCuver)
        {
            return this.GetWholeLoadPath(removePtNotOnCuver).Disps;
        }

        /// <summary>
        /// 获得所有序号
        /// </summary>
        public List<int> Orders(bool removePtNotOnCuver)
        {
            return this.GetWholeLoadPath(removePtNotOnCuver).Orders;
        }

        /// <summary>
        /// 获得结果
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="cycleList"></param>
        /// <returns></returns>
        private List<float> GetValueList(DataType dataType, List<Cycle> cycleList)
        {
            //枚举
            switch (dataType)
            {
                //等效粘滞系数
                case DataType.ViscousDampingRatio:
                    {
                        return (from cycle in cycleList
                                select cycle.GetViscousDampingRatio()).ToList();
                    }
                //割线刚度
                case DataType.SecantStiffness:
                    {
                        return (from cycle in cycleList
                                select cycle.GetSecantStiffness()).ToList();
                    }
                //割线刚度退化系数
                case DataType.SecantStiffnessRatio:
                    {
                        //获得所有割线刚度
                        var stiffnessList = this.GetValueList(DataType.SecantStiffness, cycleList);
                        //获得初始值
                        if (stiffnessList.Count == 0) return new List<float>();
                        //初始刚度
                        var iniStiffness = stiffnessList.First();
                        //计算割线刚度系数
                        var ratioList = (from stiffness in stiffnessList
                                         select iniStiffness == 0 ? 0 : 1 - stiffness / iniStiffness).ToList();
                        //防止小于0的情况
                        return (from ratio in ratioList select ratio < 0 ? 0 : ratio).ToList();
                    }
                //滞回环最大位移
                case DataType.CycleMaxDisp:
                    {
                        return (from cycle in cycleList select cycle.GetMaxDisp()).ToList();
                    }
                //滞回环最大位移 绝对值
                case DataType.AbsCycleMaxDisp:
                    {
                        return (from cycle in cycleList select Math.Abs(cycle.GetMaxDisp())).ToList();
                    }
                //卸载残余变形
                case DataType.UnloadDisp:
                    {
                        return (from cycle in cycleList
                                select cycle.GetUnloadDisp()).ToList();
                    }
                //卸载残余变形 绝对值
                case DataType.AbsUnloadDisp:
                    {
                        return (from cycle in cycleList select Math.Abs(cycle.GetUnloadDisp())).ToList();
                    }
                //卸载残余变形系数
                case DataType.UnloadDispRatio:
                    {
                        return (from cycle in cycleList select cycle.GetUnloadDispRatio()).ToList();
                    }
                //环最大承载力
                case DataType.CycleMaxForce:
                    {
                        return (from cycle in cycleList select cycle.GetMaxForce()).ToList();
                    }
                //环最大承载力
                case DataType.AbsCycleMaxForce:
                    {
                        return (from cycle in cycleList
                                select Math.Abs(cycle.GetMaxForce())).ToList();
                    }
                //环最大承载力系数
                case DataType.CycleMaxForceRatio:
                    {
                        //获得最大内力
                        var maxForce = Math.Max(Math.Abs(this.loadingPathes.ForceMaxPoint.Force),
                            Math.Abs(this.loadingPathes.ForceMinPoint.Force));
                        return (from cycle in cycleList
                                select maxForce == 0 ? 0 :
                                Math.Abs(cycle.GetMaxForce()) / maxForce).ToList();
                    }
                //累积耗能面积
                case DataType.AccumulateEnergy:
                    {
                        return (from cycle in cycleList select cycle.AccEnergy).ToList();
                    }
                //滞回环序号
                case DataType.CycleIndex:
                    {
                        return (from cycle in cycleList select (float)cycle.Index).ToList();
                    }
                default:
                    {
                        return (from cycle in cycleList select 0F).ToList();
                    }
            }
        }

        /// <summary>
        /// 获得结果
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public List<float> GetValueList(DataType dataType, bool isFilter)
        {
            //获得对象
            var cycList = this.GetCircleList(isFilter, true);
            return this.GetValueList(dataType, cycList);
        }

        /// <summary>
        /// 获得结果
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public List<float> GetValueList(DataType dataType, bool isPos, bool isFilter)
        {
            //获得对象
            var cycList = this.GetDirectionCircleList(isFilter, isPos);
            //枚举
            switch (dataType)
            {
                //等效粘滞系数
                case DataType.ViscousDampingRatio:
                    {
                        return (from cycle in cycList select cycle.GetViscousDampingRatio(isPos)).ToList();
                    }
                //割线刚度
                case DataType.SecantStiffness:
                    {
                        return (from cycle in cycList select cycle.GetSecantStiffness(isPos)).ToList();
                    }
                //割线刚度退化系数
                case DataType.SecantStiffnessRatio:
                    {
                        //获得所有割线刚度
                        var stiffnessList = this.GetValueList(DataType.SecantStiffness, isPos, isFilter);
                        //获得初始值
                        if (stiffnessList.Count == 0) return new List<float> ();
                        //初始刚度
                        var iniStiffness = stiffnessList.First();
                        //计算割线刚度系数
                        var ratioList = (from stiffness in stiffnessList
                                select iniStiffness == 0 ? 0 : 1 - stiffness / iniStiffness).ToList();
                        //防止小于0的情况
                        return (from ratio in ratioList select ratio < 0? 0: ratio).ToList();
                    }
                //滞回环最大位移
                case DataType.CycleMaxDisp:
                    {
                        return (from cycle in cycList select cycle.GetMaxDisp(isPos)).ToList();
                    }
                //滞回环最大位移 绝对值
                case DataType.AbsCycleMaxDisp:
                    {
                        return (from cycle in cycList 
                                select Math.Abs(cycle.GetMaxDisp(isPos))).ToList();
                    }
                //卸载残余变形
                case DataType.UnloadDisp:
                    {
                        return (from cycle in cycList select cycle.GetUnloadDisp(isPos)).ToList();
                    }
                //卸载残余变形 绝对值
                case DataType.AbsUnloadDisp:
                    {
                        return (from cycle in cycList 
                                select Math.Abs(cycle.GetUnloadDisp(isPos))).ToList();
                    }
                //卸载残余变形系数
                case DataType.UnloadDispRatio:
                    {
                        return (from cycle in cycList 
                                select cycle.GetUnloadDispRatio(isPos)).ToList();
                    }
                //环最大承载力
                case DataType.CycleMaxForce:
                    {
                        return (from cycle in cycList select cycle.GetMaxForce(isPos)).ToList();
                    }
                //环最大承载力
                case DataType.AbsCycleMaxForce:
                    {
                        return (from cycle in cycList 
                                select Math.Abs(cycle.GetMaxForce(isPos))).ToList();
                    }
                //环最大承载力
                case DataType.CycleMaxForceRatio:
                    {
                        //获得最大内力
                        var maxForce = isPos ? this.loadingPathes.ForceMaxPoint.Force :
                            this.loadingPathes.ForceMinPoint.Force;
                        return (from cycle in cycList
                                select maxForce == 0 ? 0 :
                                cycle.GetMaxForce(isPos) / maxForce).ToList();
                    }
            }
            return this.GetValueList(dataType, cycList);
        }

        /// <summary>
        /// 获得平滑的滞回曲线
        /// </summary>
        /// <returns></returns>
        public CycleSet GetSmoothCycleSet()
        {
            //初始化
            var cycleSet = new CycleSet();
            //构造加载、卸载路径
            cycleSet.loadingPathes = this.loadingPathes;
            //平滑
            this.CycleList.ForEach(cycle => cycleSet.CycleList.Add(cycle.GetSmoothCycle()));
            //返回对象
            return cycleSet; ;
        }

        /// <summary>
        /// 获得代数化滞回曲线
        /// </summary>
        /// <returns></returns>
        public CycleSet GetNumericalCycleSet()
        {
            //初始化
            var cycleSet = new CycleSet();
            //构造加载、卸载路径
            cycleSet.loadingPathes = this.loadingPathes;
            //平滑
            this.CycleList.ForEach(cycle => cycleSet.CycleList.Add(cycle.GetNumericalCycle()));
            //返回对象
            return cycleSet;
        }

        /// <summary>
        /// 骨架限定后的滞回曲线
        /// </summary>
        /// <returns></returns>
        public CycleSet GetPostExpCycleSet(MontForceDispObj posSkeleton,
            MontForceDispObj negSkeleton)
        {
            //初始化
            var cycleSet = new CycleSet();
            //构造加载、卸载路径
            cycleSet.loadingPathes = this.loadingPathes;
            //处理
            foreach(var cycle in this.CycleList)
            {
                cycleSet.CycleList.Add(cycle.GetPostExpCycle(posSkeleton, negSkeleton));
            }
            //返回对象
            return cycleSet;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public CycleSet()
        {
            this.CycleList = new List<Cycle>();
            this.loadingPathes = new LoadingPathSet();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="pathSet"></param>
        public CycleSet(ForceDispObj originForceDispObj) :this()
        {
            //构造加载、卸载路径
            this.loadingPathes = new LoadingPathSet(originForceDispObj);
            //初始化
            float energy = 0F;
            //遍历环
            for(int i = 0; i < this.loadingPathes.Count; i++)
            {
                //当前对象
                var curLoadPath = this.loadingPathes[i];
                //是否越界
                if(i + 1 >= this.loadingPathes.Count)
                {
                    this.CycleList.Add(new Cycle(curLoadPath, this.Count + 1, ref energy));
                    break;
                }
                //是否为24象限对象
                if (curLoadPath.isPeakOreintedInRegion24) continue;
                //获得前后两个对象
                var postLoadPath = this.loadingPathes[i + 1];
                //是否反向: 添加两个对象
                if((curLoadPath.isPosLoading && !postLoadPath.isPosLoading) ||
                    (!curLoadPath.isPosLoading && postLoadPath.isPosLoading))
                {
                    this.CycleList.Add(new Cycle(curLoadPath, postLoadPath, 
                        this.Count + 1, ref energy));
                    i++;
                }
                //同向：仅添加当前对象
                else this.CycleList.Add(new Cycle(curLoadPath, this.Count + 1, ref energy));
            }
        }
    }
}
